package cn.lxh.system.service.impl;


import cn.lxh.system.domain.Menu;
import cn.lxh.system.mapper.MenuMapper;
import cn.lxh.system.query.MenuQuery;
import cn.lxh.system.service.IMenuService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * MenuServiceImpl业务层类
 */
@Service // 该类交给spring管理
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS) // 将数据库设置成只读数据库, 此时若要进行写的操作, 会出现错误, 有事务就以事务方式执行, 没有事务就以非事务方式执行
@CacheConfig(cacheNames = "menu")
public class MenuServiceImpl implements IMenuService {

    @Autowired
    private MenuMapper menuMapper;

    /**
     * 修改菜单
     *
     * @param menu
     */
    @Transactional // 开始事务
    @Override
    @CacheEvict(key = "'menuTree'")
    public void add(Menu menu) {
        menuMapper.add(menu);
    }

    /**
     * 根据id删除菜单
     *
     * @param id
     */
    @Transactional // 开始事务
    @Override
    @CacheEvict(key = "'menuTree'")
    public void delete(Long id) {
        menuMapper.delete(id);
    }

    /**
     * 修改菜单
     *
     * @param menu
     */
    @Transactional // 开始事务
    @Override
    @CacheEvict(key = "'menuTree'")
    public void update(Menu menu) {
        menuMapper.update(menu);
    }

    /**
     * 根据id查询单个菜单
     *
     * @param id
     * @return
     */
    @Override
    public Menu findOne(Long id) {
        return menuMapper.findOne(id);
    }

    /**
     * 查询所有菜单
     *
     * @return
     */
    @Override
    public List<Menu> findAll() {
        return menuMapper.findAll();
    }

    /**
     * 根据id批量删除菜单
     *
     * @param ids
     */
    @Transactional // 开始事务
    @Override
    @CacheEvict(key = "'menuTree'")
    public void patchDelete(Long[] ids) {
        menuMapper.patchDelete(ids);
    }

    /**
     * 分页查询
     *
     * @param menuQuery
     * @return
     */
    @Override
    public PageInfo<Menu> queryPage(MenuQuery menuQuery) {
        // 开启分页, 它只对紧挨着下面的第一个查询所有的sql语句生效(1. 先查询总数量total 2. 根据application.yml中驱动名自动实现分页,如果是mysql就用limit
        // 3. 自动计算limit的第一个值: limit a, b
        PageHelper.startPage(menuQuery.getCurrentPage(), menuQuery.getPageSize());
        // 查询所有
        List<Menu> list = menuMapper.queryPage(menuQuery);
        // 返回对象中有: list当前页分页数据和total总条数
        return new PageInfo<>(list);
    }

    /**
     * 获取菜单树
     *
     * @return
     */
    private List<Menu> getMenuTree() {
        // 创建一个list集合用于保存菜单树数据
        List<Menu> menuTree = new ArrayList<>();
        // 查询所有菜单
        List<Menu> menuList = menuMapper.findAll();
        // 创建一个map集合, 用于保存菜单, key为菜单id, value为菜单对象
        Map<Long, Menu> menuMap = new HashMap<>();
        // 遍历menuList集合
        for (Menu menu : menuList) {
            // 将菜单对象存入map集合
            menuMap.put(menu.getId(), menu);
        }

        // 遍历menuList集合
        for (Menu menu : menuList) {
            // 判断菜单对象是否有父菜单id
            if (menu.getParentId() == null) { // 顶级菜单
                // 顶级菜单直接放入menuTree集合中
                menuTree.add(menu);
            } else { // 有父菜单id
                // 获取父菜单id
                Long parentId = menu.getParentId();
                // 根据parentId查询父菜单对象
                Menu parentMenu = menuMap.get(parentId);
                // 判断parentType是否为null
                if (parentMenu != null) { // 防止parentMenu为null
                    // 获取父菜单对象的子菜单集合
                    List<Menu> children = parentMenu.getChildren();
                    // 将循环的菜单对象放进该父菜单对象的子菜单集合中
                    children.add(menu);
                }
            }
        }
        return menuTree;
    }

    /**
     * 获取菜单树
     *
     * @return
     */
    @Override
    @Cacheable(key = "'menuTree'")
    public List<Menu> menuTree() {
/*        // 直接从Redis中取
        Object obj = redisTemplate.opsForValue().get("typeTree");
        if (obj == null) { // Redis中查询不到
            // 从数据库取
            List<Menu> typeTree = getTypeTree();
            // 再将typeTree存入Redis
            redisTemplate.opsForValue().set("typeTree", typeTree);
            return typeTree;
        }
        // 在Redis中查询到了, 直接返回
        return (List<Menu>) obj;*/
        return getMenuTree();
    }
}
